﻿using System;
using System.Linq;
using System.Security.Claims;
using K9Nano.Configuration.Startup;
using K9Nano.Dependency;
using K9Nano.MultiTenancy;
using K9Nano.Share;
using K9Nano.Share.Exceptions;

namespace K9Nano.Runtime
{
    public class ClaimSessionContext : SessionContextBase, ISessionContext, IScopedDependency
    {
        private readonly ITenantResolverManager _tenantResolverManager;
        private readonly IClaimAccessor _claimAccessor;

        public ClaimSessionContext(IMultiTenancyConfig multiTenancyConfig,
            IAmbientScopeProvider<SessionOverride> sessionOverrideScopeProvider,
            ITenantResolverManager tenantResolverManager,
            IClaimAccessor claimAccessor) : base(multiTenancyConfig, sessionOverrideScopeProvider)
        {
            _tenantResolverManager = tenantResolverManager;
            _claimAccessor = claimAccessor;
        }

        protected override Guid? GetTenantId()
        {
            if (_claimAccessor.ClaimsPrincipal == null)
            {
                return null;
            }

            var claim = GetClaim(K9SharedConstants.TenantIdClaimType);
            if (!string.IsNullOrEmpty(claim))
            {
                if (Guid.TryParse(claim, out var tid))
                {
                    return tid;
                }
                throw new K9Exception("Tenant ID in claim is not a valid GUID");
            }

            if (UserId == null)
            {
                return _tenantResolverManager.ResolveTenantId();
            }

            return null;
        }

        protected override Guid? GetUserId()
        {
            var claim = GetClaim(K9SharedConstants.UserIdClaimType);

            if (claim == null) return null;

            return Guid.TryParse(claim, out var userId) ? userId : (Guid?)null;
        }

        protected override string[] GetRoles()
        {
            if (_claimAccessor.ClaimsPrincipal != null)
            {
                // TODO ISessionContext.Use()会导致当前用户与Claim中的用户不一致，此时如何获取用户角色
                if (UserId == GetUserId())
                {
                    var roles = GetClaim(K9SharedConstants.RoleClaimType);
                    if (!string.IsNullOrWhiteSpace(roles))
                    {
                        return roles.Split(',', StringSplitOptions.RemoveEmptyEntries);
                    }
                }
            }

            return null;
        }

        public override string GetClaim(string claimType)
        {
            return _claimAccessor.ClaimsPrincipal?.Claims
                  .FirstOrDefault(x => x.Type == claimType)?.Value;
        }

        protected override string[] GetScopes()
        {
            return _claimAccessor.ClaimsPrincipal?.Claims
                .Where(x => x.Type == "scope")
                .Select(x => x.Value)
                .ToArray();
        }
    }
}